package hichecker.university;

import hichecker.controller.Config;
import hichecker.ui.components.icon_factory.IconFactory.IconType;
import hichecker.university.jaxb.HashMapAdapter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.UUID;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

/**
 * Class representing a partial exam requirement
 */
@XmlType( propOrder = {"series", "grades", "gradingKey"})
public class PTL extends Requirement {
	private @XmlAttribute float gradePercentage;

	private @XmlJavaTypeAdapter(HashMapAdapter.class) HashMap<Student, Float> grades;
	private @XmlElement List<PTLSeries> series;
	private @XmlElement GradingKey gradingKey;

	/**
	 * Creates a new ptl and sets a default name
	 */
	public PTL() {
		super();
		setName(Config.NEW_VALUE_PTL_NAME);
	}

	/**
	 * Creates a new ptl with a referenced id
	 *
	 * @param id
	 */
	public PTL(UUID id) {
		super(id);
	}

	/**
	 * Creates a new ptl and copies all values out of the referenced ptl
	 *
	 * @param ptl
	 */
	public PTL(PTL ptl) {
		super(ptl);

		grades = new HashMap<Student, Float>();
		for (Entry<Student, Float> entry : ptl.getGrades().entrySet())
			grades.put(entry.getKey(), entry.getValue());

		series = new ArrayList<PTLSeries>();
		for (PTLSeries ser : ptl.getSeries())
			series.add(new PTLSeries(ser));

		if (ptl.getGradingKey() == null) return;
		gradingKey = new GradingKey(ptl.gradingKey);
	}

	/**
	 * @return the grades of all students
	 */
	@XmlTransient
	public HashMap<Student, Float> getGrades() {
		return grades = (grades == null ? new HashMap<Student, Float>() : grades);
	}

	/**
	 * Returns the grade of the referenced student
	 *
	 * @param student
	 * @return -1 if the student didn't gain a grade yet
	 */
	public float getGrade(Student student) {
		if (grades == null)
			grades = new HashMap<Student, Float>();
		return grades.get(student) == null ? -1 : grades.get(student);
	}

	/**
	 * @param grades the grades of all students to set
	 */
	public void setGrades(HashMap<Student, Float> grades) {
		this.grades = grades;
	}

	/**
	 * @return the grading key for alle grades
	 */
	@XmlTransient
	public GradingKey getGradingKey() {
		return gradingKey;
	}

	/**
	 * @param gradingKey the grading ket to set
	 */
	public void setGradingKey(GradingKey gradingKey) {
		this.gradingKey = gradingKey;
	}

	/**
	 * Returns the percentage the ptl grade has on the whole course grade
	 *
	 * @return A value between 0..1
	 */
	@XmlTransient
	public float getGradePercentage() {
		return gradePercentage;
	}

	/**
	 * Sets the percentage the ptl grade has on the whole course grade
	 *
	 * @param gradePercentage
	 *            A value between 0..1
	 */
	public void setGradePercentage(float gradePercentage) {
		this.gradePercentage = gradePercentage;
	}

	/**
	 * @return the list of series related to this ptl
	 */
	@XmlTransient
	public List<PTLSeries> getSeries() {
		return series = (series == null ? new ArrayList<PTLSeries>() : series);
	}

	/**
	 * @param series the series to add
	 */
	public void addSeries(PTLSeries series) {
		if (series instanceof PTLSeries)
			getSeries().add(series);
	}

	/**
	 * Sets the list of series to {@code null}
	 */
	public void clearSeries() {
		series = null;
	}

	/**
	 * Indicates whether a specific series is part of this ptl
	 *
	 * @param series
	 * @return
	 */
	public boolean containsSeries(Series series) {
		if (this.series == null) return false;
		for (Series ser : this.series) {
			if (series.equals(ser)) return true;
		}
		return false;
	}

	@Override
	public float getMaxPoints() {
		float sum = 0;
		if (series == null)
			series = new ArrayList<PTLSeries>();
		for (PTLSeries ser : series)
			sum += ser.getSumMax();
		return sum;
	}

	@Override
	public float getSumPoints(Student student) {
		float sum = 0;
		if (series == null)
			series = new ArrayList<PTLSeries>();
		for (PTLSeries ser : series)
			sum += ser.getSumGainedPoints(student);
		return sum;
	}

	@Override
	public List<UniversityPart> getSubParts() {
		List<UniversityPart> parts = new ArrayList<UniversityPart>();
		parts.addAll(getSeries());
		return parts;
	}

	@Override
	public UUID addSubPart(int type) {
		PTLSeries series = new PTLSeries();
		getSeries().add(series);
		return series.getID();
	}

	@Override
	public void removeSubPart(UUID id) {
		getSeries().remove(new PTLSeries(id));
	}

	@Override
	public IconType getIcon() {
		return IconType.FOLDER_PTL;
	}

	@Override
	public IconType getAddIcon() {
		return IconType.ADD_PTL;
	}
}
